//
//  ST_JVAlamofire .swift
//  SmartKeeperTwo
//
//  Created by DouLeiZhang on 2017/5/31.
//  Copyright © 2017年 DouLeiZhang. All rights reserved.
//

import Foundation
import Qiniu
import Alamofire
import SwiftyJSON
//import KeychainAccess
import SwiftyUserDefaults
import RealmSwift
import DeviceKit
import SwifterSwift
import RxAlamofire
import RxSwift
import RxCocoa

public struct ST_NetworkError: Error {
    let code:Int
    let e:String
}

enum ST_TianNetworkStatus:Int {
    case reachable = 0,notReachable = 1
}

class ST_NetworkStatusManager {
    
    //shared instance
    static let shared = ST_NetworkStatusManager()
    
    /// 网络变化
    let networkStatusObservable = PublishRelay<ST_TianNetworkStatus>()
    
    let reachabilityManager = Alamofire.NetworkReachabilityManager(host: "www.baidu.com")
    
    func start_network_reachability_observer() {
        
        reachabilityManager?.startListening(onUpdatePerforming: { (status) in
            switch status {
            case .notReachable:
                //                print("The network is not reachable")
                self.networkStatusObservable.accept(.notReachable)
                
            case .unknown :
                //                print("It is unknown whether the network is reachable")
                self.networkStatusObservable.accept(.notReachable)
                //            case .unknown :
                
            case .reachable(.ethernetOrWiFi):
                //                print("The network is reachable over the WiFi connection")
                self.networkStatusObservable.accept(.reachable)
                
            case .reachable(.cellular):
                //                print("The network is reachable over the WWAN connection")
                
                self.networkStatusObservable.accept(.reachable)
            }
        })
        
    }
}

//MARK:-  SSL Cer

///SSL Pinned session
extension Session{
    
    public static let tainSession = Session.init(serverTrustManager: ServerTrustManager(evaluators: ["www.jingniaoapps.com" : PinnedCertificatesTrustEvaluator()]))
    
}

class ST_TIANSessionProvider {
    
    //shared instance
    static let shared = ST_TIANSessionProvider()
    
    private init(){}
    
    
    fileprivate var pinnedSSLCer = false
    
    fileprivate var fetchingSSLConfig = false
    
    fileprivate func fetch_s_s_l_cer_config(){
        
        if fetchingSSLConfig{
            return
        }
        
        fetchingSSLConfig = true
        
        let afRequest = AF.request("http://new.jingniaoapps.com/vdsns/sslConf/index/v2.json", method: .post, encoding: URLEncoding.init(destination: URLEncoding.Destination.methodDependent, arrayEncoding: URLEncoding.ArrayEncoding.brackets, boolEncoding: URLEncoding.BoolEncoding.literal))
        
        afRequest.cURLDescription { description in
            
#if DEBUG
            
            var logStr = "------------------\n" + description
            
            if firstLog{
                firstLog = false
                logStr = "------------------第一次运行\n" + logStr
            }
            
            print(logStr)
            
            //        print(logStr, to: &ThursdayLogger)
#endif
            
        }.response(queue:  DispatchQueue.main) { (response) in
            
            
            
            guard let data = response.data , let swiftyJsonVar = try? JSON.init(data: data) else{
                
                return
            }
            
            if swiftyJsonVar["data"]["is_open"].boolValue{
                self.pinnedSSLCer = true
            }
            
        }
    }
    
    
    static func generate_s_s_l_session()->Session{
            return AF
    }
    
}

//MARK:- network Request


func JVGenerateParameters(parameters: Parameters?) -> Parameters {
    
    var request_data = Parameters()
    
    //    登录之后需要参数
    if let account = ST_BTUserInfoManager.shared.current_account_info{
        
        request_data.updateValue(account.token, forKey: "token")
        
        request_data.updateValue(account.accid, forKey: "accid")
        
    }else if let registerInfo = ST_RegisterMonitor.shared.regist_response_account(){
        
        request_data.updateValue(registerInfo.token, forKey: "token")
        
        request_data.updateValue(registerInfo.accid, forKey: "accid")
    }
    
    
    request_data.updateValue(Date().unixTimestamp.int.string, forKey: "_timestamp")
    
    if let smDeviceId = SmAntiFraud.shareInstance()?.getDeviceId(){
        request_data.updateValue(smDeviceId, forKey: "device_id")
        print("数美设备Id:",smDeviceId)
    }else{
        print("数美设备Id:空")
    }
    
    request_data.updateValue(SC.tianIDFA, forKey: "idfa")
    
    
    if let param = parameters {
        
        for item in param {
            
            if let fValue = item.value as? Float{
                request_data.updateValue(fValue.string, forKey: item.key)
            }else if let fValue = item.value as? CGFloat{
                request_data.updateValue(fValue.string, forKey: item.key)
            }else if let fValue = item.value as? Double{
                request_data.updateValue(fValue.string, forKey: item.key)
            }
            else{
                request_data.updateValue(item.value, forKey: item.key)
            }
        }
        
    }
    
    //    print("签名之前的参数",request_data)
    
    let sign = CreateSignature(parameters: request_data)
    
    request_data.updateValue(sign, forKey: "_signature")
    
    //    print("签名之后的参数",request_data)
    
    return request_data
}

func CreateSocketSignature(parameters:Dictionary<String, String>)->String{
    
    return CreateSignature(parameters: parameters)
    
}

private func CreateSignature(parameters:Parameters)->String{
    
    var array = parameters.map { (item) -> String in
        return String.init(format: "%@=%@", item.key,String.init(describing: item.value))
    }
    
    array.sort()
    
    let subStr = "vdsns"+appVersion+"dcyfyf"+array.joined(separator: "&")
    
    //    print("加密之前的md5_string:",subStr)
    
    return subStr.md5_string
}

fileprivate var _baseHeader:[String:String]?

fileprivate var baseHeader:[String:String] = {
    
    if let param = _baseHeader{
        return param
    }else{
        
        var headParam = [String:String]()
        
        headParam.updateValue("iOS", forKey: "os")
        
        headParam.updateValue("iOS_MMA_"+(Device.current.systemVersion ?? "非法"), forKey: "chnl")
        
        headParam.updateValue(Device.identifier, forKey: "brand")
        
        headParam.updateValue(appVersion, forKey: "app-vrn")
        
        headParam.updateValue("MMA", forKey: "app-resource")
        
        _baseHeader = headParam
        
        return headParam
    }
    
}()

fileprivate var firstLog = true


func JVGenerateHeaders(headers: [String:String]?) -> [String:String] {
    
    var headParam:[String:String]!
    
    if let param = headers {
        headParam = param
    }else{
        headParam = [String:String]()
    }
    
    baseHeader.forEach { (arg0) in
        let (key, value) = arg0
        headParam.updateValue(value, forKey: key)
    }
    
    //    headParam.updateValue("wemew V1.0", forKey: "User-Agent")
    
    return headParam
}


public func TIANSession(requestUrl:String,parameters: Parameters? = nil,headers: [String:String]? = nil) -> Observable<Result<JSON,ST_NetworkError>>{
    
    let observable:Observable<(HTTPURLResponse, Data)>
    
    if PH.notRestrictedBaseConfigAPISets.contains(requestUrl){
        
        observable = sessionGenerator(requestUrl: requestUrl, parameters: parameters, headers: headers)
        
    }else{
        
        observable = SCComponets.config_component.boot_config_observer.filter({ $0 == .finished }).flatMapLatest ({ _ in sessionGenerator(requestUrl: requestUrl, parameters: parameters, headers: headers) })
        
    }
    
    return observable.map({ arg -> Result<JSON,ST_NetworkError> in
        
        let result = TianDataMapToResult(arg.1)
#if DEBUG
        print("url=",arg.0.url ?? "","----\n",result)
#endif
        return result
        
    })
}



fileprivate func TianDataMapToResult(_ data:Data?)-> Result<JSON,ST_NetworkError>{
    
    guard let d = data, let json = try? JSON(data: d) else{
        return Result.failure(ST_NetworkError(code: 0, e: "服务器异常请稍后再试"))
    }
    
    switch json["code"].intValue {
    case 200:
        return Result.success(json)
    case 426:
        main_thread_execute(afterDelay: 1.5, block: {
            
            if let upgradeText = json["msg"].string{
                
                ST_BTUpgradeController.upgradeNotification(text: upgradeText, forceUpgrade: true)
            }
        })
        return Result.failure(ST_NetworkError(code: 426, e: json["msg"].stringValue))
        
    case 403:
        
        ST_BTUserInfoManager.shared.signOut()
        
        
        return Result.failure(ST_NetworkError(code: 403, e: json["msg"].stringValue))
        
    default:
        return Result.failure(ST_NetworkError(code: json["code"].intValue, e: json["msg"].stringValue))
    }
}


fileprivate func sessionGenerator(requestUrl:String,parameters: Parameters? = nil,headers: [String:String]? = nil)->Observable<(HTTPURLResponse, Data)>{
    
    let request_data = JVGenerateParameters(parameters: parameters)
    
    let headParam = JVGenerateHeaders(headers: headers)
    
    return ST_TIANSessionProvider.generate_s_s_l_session().rx.request(.post, requestUrl, parameters: request_data, encoding: URLEncoding.init(destination: URLEncoding.Destination.methodDependent, arrayEncoding: URLEncoding.ArrayEncoding.brackets, boolEncoding: URLEncoding.BoolEncoding.literal), headers: HTTPHeaders.init(headParam), interceptor: nil).flatMap { dataRequest -> Observable<(HTTPURLResponse, Data)> in
        
#if DEBUG
        dataRequest.cURLDescription { str in
            print(str)
        }
#endif
        return dataRequest.rx.responseData()
        
    }
}





public func TIANRequest(
    _ url: String,
    method: HTTPMethod = .post,
    parameters: Parameters? = nil,
    encoding: ParameterEncoding = URLEncoding.init(destination: URLEncoding.Destination.methodDependent, arrayEncoding: URLEncoding.ArrayEncoding.brackets, boolEncoding: URLEncoding.BoolEncoding.literal),
    headers: [String:String]? = nil,
    queue:DispatchQueue? = nil,
    success:@escaping (JSON)->(),
    failure:@escaping (Int,String)->())->DataRequest?
{
    //    其他接口必须配置接口成功才能请求
//    if PH.notRestrictedBaseConfigAPISets.contains(url) == false,SCComponets.config_component.boot_config_observer.value != .finished {
//        
//        failure(0,"请稍后..")
//        
//        return nil
//    }
    
    let request_data = JVGenerateParameters(parameters: parameters)
    
    let headParam = JVGenerateHeaders(headers: headers)
    
    let afRequest = ST_TIANSessionProvider.generate_s_s_l_session().request(url, method: method, parameters: request_data, encoding: encoding, headers: HTTPHeaders.init(headParam))
    
#if DEBUG
    afRequest.cURLDescription { str in
        print(str)
    }
#endif
    
    afRequest.response(queue: queue ?? DispatchQueue.main) { (response) in
        
        let result = TianDataMapToResult(response.data)
        
#if DEBUG
        print("url=",response.request?.url ?? "","----\n",result)
#endif
        switch result {
        case .success(let json):
            success(json)
        case .failure(let error):
            failure(error.code, error.e)
        }
    }
    
    return afRequest
}



public func JVrequest(
    _ url: String,
    method: HTTPMethod = .post,
    parameters: Parameters? = nil,
    encoding: ParameterEncoding = URLEncoding.init(destination: URLEncoding.Destination.methodDependent, arrayEncoding: URLEncoding.ArrayEncoding.brackets, boolEncoding: URLEncoding.BoolEncoding.literal),
    headers: [String:String]? = nil,
    queue:DispatchQueue? = nil,
    success:@escaping (JSON)->(),
    failure:@escaping (Int,String)->()){
        
        
        _ = TIANRequest(url, method: method, parameters: parameters, encoding: encoding, headers: headers , queue: queue) { (json) in
            success(json)
        } failure: { (code, err) in
            failure(code,err)
        }
        
        
    }


func JVUpload(videoPath:String,coverImage:Data,imageCloudKey:String = UUID().uuidString , videoCloudKey:String =  UUID().uuidString ,uploadProgress:@escaping (Float)->(),
              success:@escaping (_ imgKey:String,_ videoKey:String)->(),
              failure:@escaping (Int,String)->()) {
    
    //    step 0 : 上传缩略图
    
    JVUpload(fileKey: imageCloudKey, data: coverImage, uploadProgress:  { (f) in
        
        let p = f*0.2
        
        //        print("我很想知道：",p)
        
        uploadProgress(p)
        
    }, success: { (json) in
        
        //    step 1 : 上传视频
        
        guard let cert = NSData(contentsOfFile: videoPath) else{
            
            return
        }
        
        JVUpload(fileKey: videoCloudKey, data: cert as Data, uploadProgress:  { (f) in
            
            let p = f*0.8+0.2
            
            //            print("我很想知道：",p)
            
            uploadProgress(p)
            
        }, success: { (j) in
            
            success(imageCloudKey, videoCloudKey)
            
        } ,failure: { (c, e) in
            
            failure(c,e)
        })
        
        
    } ,failure: { (code, err) in
        
        failure(code,err)
    })
}


//MARK: -
func kkUUU(success:@escaping (JSON)->(),
           failure:@escaping (Int,String)->()){
    
    JVrequest(PH.fetchQNApi) { (json) in
        
        success(json)
        
    } failure: { (code, err) in
        
        failure(code,err)
    }
    
    
}


//MARK:- upload File
func JVUpload(fileKey: String = "",
              data:Data,
              uploadProgress:@escaping (Float)->(),
              success:@escaping (JSON)->(),
              failure:@escaping (Int,String)->())
{
    
    kkUUU(success: { (json) in
        
        print("七牛接口返回：",json["data"]["sign"].stringValue)
        
        
        guard var safeData = json["data"]["sign"].stringValue.safe_base_64_data else{
            main_thread_execute {
                failure(0,"未知错误❌")
            }
            
            return
        }
        
        let kkkk =  "sd1245s8".data(using: .utf8)!
        
        for i in 0 ..< safeData.count {
            let handleValue = kkkk[i % kkkk.count]
            safeData[i] ^= handleValue
        }
        
        guard let utf8_kkk = String(bytes: safeData, encoding: .utf8) else{
            
            main_thread_execute {
                failure(0,"上传错误未知")
            }
            return
        }
        
        var aaa = utf8_kkk.charactersArray
        
        if aaa.count >= 77{
            
            let x = Array(aaa[0..<71])
            
            let y = Array(aaa[77...aaa.count-1])
            
            var bbb = Array(aaa[71...76])
            
            bbb.reverse()
            
            aaa = x + bbb + y
        }
        
        let account_qntk = String(aaa)
        
        
        main_thread_execute {
            
            let manager = QNUploadManager.init()
            
            let option = QNUploadOption.init(progressHandler: { key , progress in
                
                main_thread_execute {
                    
                    uploadProgress(progress)
                    
                }
                
            })
            
            print("七牛Token:\(account_qntk)")
            
            manager?.put(data, key: fileKey, token: account_qntk, complete: { (info, str, resp) in
                
                if let dict = resp{
                    main_thread_execute {
                        success(JSON(dict))
                    }
                }else{
                    
                    if let eInfo = info{
                        main_thread_execute {
                            print("上传错误：",eInfo.error ?? "无")
                            failure(Int(eInfo.statusCode),"上传错误未知")
                        }
                    }else{
                        main_thread_execute {
                            failure(0,"上传错误未知")
                        }
                    }
                }
            }, option: option)
        }
        
    }, failure: failure)
    
    
    
    
}




//MARK: - OBJC  Method
class ST_JVAlamofire: NSObject {
    //    MARK: api
    @objc static let obj_faceMatchApi = PH.faceMatchApi
    
    //    MARK: Method
    @objc static func upload(fileKey: String = "",data:Data,uploadProgress:@escaping (Float)->(),success:@escaping (Dictionary<String, Any>)->(),failure:@escaping (Int,String)->()){
        
        
        JVUpload(fileKey: fileKey, data: data, uploadProgress: uploadProgress, success: { (json) in
            
            if let dict = json.dictionaryObject{
                success(dict)
            }else{
                success(["":""])
            }
        }, failure: failure)
        
    }
    
    
    
    @objc static  func request(
        _ url: String,
        parameters: Parameters? = nil,
        success:@escaping (Dictionary<String, Any>)->(),
        failure:@escaping (Int,String)->())
    {
        
        JVrequest(url,parameters: parameters,success: { (json) in
            
            if let dict = json.dictionaryObject{
                success(dict)
            }else{
                success(["":""])
            }
            
        }, failure: failure)
        
        
    }
    
    
    @objc static func download(url:String,savedPath:String,success:@escaping ()->(),
                               failure:@escaping (Int,String)->()){
        
        
        
        AF.download(url, method: HTTPMethod.get, encoding: JSONEncoding.default, to:  { (url, response) -> (destinationURL: URL, options: DownloadRequest.Options) in
            
            return (destinationURL:URL(fileURLWithPath: savedPath),options:[.removePreviousFile, .createIntermediateDirectories])
            
        })
        .responseData { response in
            
            if let error = response.error{
                failure(error.responseCode ?? -1,error.localizedDescription)
            }else{
                success()
            }
        }
    }
}
